package dao;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import parsers.CommonMethods;
import parsers.calendar.CalendarsParser;
import parsers.calendar.MainCalendarsParser;
import parsers.group.DirectionsParser;
import parsers.group.GroupParser;
import parsers.lectureRoom.BuildingsParser;
import parsers.lectureRoom.LectureRoomParser;
import parsers.lectureRoom.LectureRoomsParser;
import parsers.reservation.ReservationLRParser;
import parsers.reservation.ReservationTParser;
import parsers.teacher.TeacherParser;
import parsers.teacher.TeachersParser;
import util.Utilities;

import model.Building;
import model.Calendar;
import model.CalendarList;
import model.Department;
import model.Direction;
import model.Group;
import model.LectureRoom;
import model.Reservation;
import model.Teacher;

public class MainDataAccessObject
{
	/**
	 * List of departments
	 */
	private Map<String, Department> departments = new HashMap<String, Department>();
	
	/**
	 * List of departments with teachers
	 */
	private Map<String, Department> departmentsWithTeachers = new HashMap<String, Department>();
	
	/**
	 * List of teachers with timetable
	 */
	private Map<String, Teacher> teachersTimetable = new HashMap<String, Teacher>();
	
	/**
	 * List of reservations of teachers
	 */
	private Map<String, Reservation> teachersReservations = new HashMap<String, Reservation>();
	
	/**
	 * List of departments with directions
	 */
	private Map<String, Department> departmentsWithDirections = new HashMap<String, Department>();
	
	/**
	 * List of directions with groups
	 */
	private Map<String, Direction> directionsWithGroups = new HashMap<String, Direction>();
	
	/**
	 * List of groups with timetable
	 */
	private Map<String, Group> groupsTimetable = new HashMap<String, Group>();
	
	/**
	 * List of buildings
	 */
	private Map<String, Building> buildings = new HashMap<String, Building>();
	
	/**
	 * List of buildings with lecture rooms
	 */
	private Map<String, Building> buildingsWithLectureRooms = new HashMap<String, Building>();
	
	/**
	 * List of lecture rooms with timetable
	 */
	private Map<String, LectureRoom> lectureRoomsTimetable = new HashMap<String, LectureRoom>();
	
	/**
	 * List of reservations of lecture rooms
	 */
	private Map<String, Reservation> lectureRoomsReservations = new HashMap<String, Reservation>();
	
	/**
	 * List of general calendars
	 */
	private Map<String, CalendarList> calendarList = new HashMap<String, CalendarList>();
	
	/**
	 * List of calendars with entries
	 */
	private Map<String, Calendar> calendars = new HashMap<String, Calendar>();
	
	private long startTime;
	private Map<String, String> files = new HashMap<String, String>();
	
	public MainDataAccessObject()
	{
		initFiles();
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising departmentsWithDirections: ");
		if( (new File(files.get("0"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("0") + ") ");
			departmentsWithDirections = (Map<String, Department>) util.Utilities.deserialize(files.get("0"));
		}
		else
		{
			initDepartmentsWithDirections();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising directionsWithGroups: ");
		if( (new File(files.get("1"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("1") + ") ");
			directionsWithGroups = (Map<String, Direction>) util.Utilities.deserialize(files.get("1"));
		}
		else
		{
			initDirectionsWithGroups();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising groupsTimetable: ");
		if( (new File(files.get("2"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("2") + ") ");
			groupsTimetable = (Map<String, Group>) util.Utilities.deserialize(files.get("2"));
		}
		else
		{
			initGroupsTimetable();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/

		/*************************************************************/
		startTime();
		System.out.print("Initialising departments: ");
		if( (new File(files.get("3"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("3") + ") ");
			departments = (Map<String, Department>) util.Utilities.deserialize(files.get("3"));
		}
		else
		{
			initDepartments();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising departmentsWithTeachers: ");
		if( (new File(files.get("4"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("4") + ") ");
			departmentsWithTeachers = (Map<String, Department>) util.Utilities.deserialize(files.get("4"));
		}
		else
		{
			initDepartmentsWithTeachers();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising teachersTimetable: ");
		if( (new File(files.get("5"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("5") + ") ");
			teachersTimetable = (Map<String, Teacher>) util.Utilities.deserialize(files.get("5"));
		}
		else
		{
			initTeachersTimetable();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/

		/*************************************************************/
		startTime();
		System.out.print("Initialising buildings: ");
		if( (new File(files.get("6"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("6") + ") ");
			buildings = (Map<String, Building>) util.Utilities.deserialize(files.get("6"));
		}
		else
		{
			initBuildings();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising buildingsWithLectureRooms: ");
		if( (new File(files.get("7"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("7") + ") ");
			buildingsWithLectureRooms = (Map<String, Building>) util.Utilities.deserialize(files.get("7"));
		}
		else
		{
			initBuildingsWithLectureRooms();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising lectureRoomsTimetable: ");
		if( (new File(files.get("8"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("8") + ") ");
			lectureRoomsTimetable = (Map<String, LectureRoom>) util.Utilities.deserialize(files.get("8"));
		}
		else
		{
			initLectureRoomsTimetable();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising calendarList and calendars: ");
		if( (new File(files.get("9"))).exists() && (new File(files.get("10"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("9") + ", " + files.get("10") + ") ");
			calendarList = (Map<String, CalendarList>) util.Utilities.deserialize(files.get("9"));
			calendars = (Map<String, Calendar>) util.Utilities.deserialize(files.get("10"));
		}
		else
		{
			initCalendarListAndCalendars();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising teachersReservations: ");
		if( (new File(files.get("11"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("11") + ") ");
			lectureRoomsTimetable = (Map<String, LectureRoom>) util.Utilities.deserialize(files.get("11"));
		}
		else
		{
			initTeachersReservations();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
		
		/*************************************************************/
		startTime();
		System.out.print("Initialising lectureRoomsReservations: ");
		if( (new File(files.get("12"))).exists() )
		{
			System.out.print("(find serialized file " + files.get("12") + ") ");
			lectureRoomsTimetable = (Map<String, LectureRoom>) util.Utilities.deserialize(files.get("12"));
		}
		else
		{
			initLectureRoomsReservations();
		}
		System.out.println(countTime() + " ms");
		/*************************************************************/
	}
	
	private void initFiles()
	{
		files.put("0", Utilities.makeFileName("departmentsWithDirections"));
		files.put("1", Utilities.makeFileName("directionsWithGroups"));
		files.put("2", Utilities.makeFileName("groupsTimetable"));
		files.put("3", Utilities.makeFileName("departments"));
		files.put("4", Utilities.makeFileName("departmentsWithTeachers"));
		files.put("5", Utilities.makeFileName("teachersTimetable"));
		files.put("6", Utilities.makeFileName("buildings"));
		files.put("7", Utilities.makeFileName("buildingsWithLectureRooms"));
		files.put("8", Utilities.makeFileName("lectureRoomsTimetable"));
		files.put("9", Utilities.makeFileName("calendarList"));
		files.put("10", Utilities.makeFileName("calendars"));
		files.put("11", Utilities.makeFileName("teachersReservations"));
		files.put("12", Utilities.makeFileName("lectureRoomsReservations"));
	}

	private void initDepartmentsWithDirections()
	{
		try
		{
			parsers.group.DepartmentsParser dp = new parsers.group.DepartmentsParser();
			ArrayList<Department> departmentsLocal = dp.parse(new URL("http://plan.uz.zgora.pl/grupy_lista_kierunkow.php"));
			
			for (int i = 0; i < departmentsLocal.size(); i++)
			{
				departmentsWithDirections.put(departmentsLocal.get(i).getId(), departmentsLocal.get(i));
			}
		} 
		catch (MalformedURLException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	private void initDirectionsWithGroups()
	{
		Iterator<Department> departments = departmentsWithDirections.values().iterator();
		
		while(departments.hasNext())
		{
			Department department = departments.next();
			ArrayList<Direction> directions = department.getDirections();
			
			for (int i = 0; i < directions.size(); i++)
			{
				Direction direction = new Direction(directions.get(i).getName());
				direction.setId(directions.get(i).getId());
				direction.setLink(CommonMethods.parseLink(directions.get(i).getLink()));
				
				DirectionsParser dp = new DirectionsParser(direction);
				
				try
				{
					dp.parse(true);
					directionsWithGroups.put(direction.getId(), direction);
				} 
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	private void initGroupsTimetable()
	{
		Iterator<Direction> directions = directionsWithGroups.values().iterator();
		
		while(directions.hasNext())
		{
			
			Direction direction = directions.next();
			ArrayList<Group> groups = direction.getGroups();
			
			for (int i = 0; i < groups.size(); i++)
			{
				Group group = new Group(groups.get(i).getName(), groups.get(i).getDescription());
				group.setId(groups.get(i).getId());
				group.setLink(CommonMethods.parseLink(groups.get(i).getLink()));
				
				GroupParser gp = new GroupParser(group);
				try
				{
					gp.parse(true);
					groupsTimetable.put(group.getId(), group);
				} 
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	private void initDepartments()
	{
		parsers.teacher.DepartmentsParser dtp = new parsers.teacher.DepartmentsParser();
		
		try
		{
			ArrayList<Department> departmentsLocal = dtp.parse(new URL("http://plan.uz.zgora.pl/nauczyciel_lista_wydzialow.php?pTyp=P"));
			
			for (int i = 0; i < departmentsLocal.size(); i++)
			{
				departments.put(departmentsLocal.get(i).getId(), departmentsLocal.get(i));
			}
		} 
		catch (MalformedURLException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	private void initDepartmentsWithTeachers()
	{
		Iterator<Department> departmentsLocal = departments.values().iterator();
		while(departmentsLocal.hasNext())
		{
			Department department = departmentsLocal.next();
			Department dept = new Department(department.getName());
			dept.setLink(CommonMethods.parseLink(department.getLink()));
			dept.setId(department.getId());
			
			TeachersParser tp = new TeachersParser(dept);
			
			try
			{
				tp.parse(true);
				departmentsWithTeachers.put(dept.getId(), dept);
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	private void initTeachersTimetable()
	{
		Iterator<Department> departmentsLocal = departmentsWithTeachers.values().iterator();
		while(departmentsLocal.hasNext())
		{
			Department department = departmentsLocal.next();
			ArrayList<Teacher> teachers = department.getTeachers();
			
			for (int i = 0; i < teachers.size(); i++)
			{
				Teacher teacher = new Teacher(teachers.get(i).getName(), teachers.get(i).getUnit());
				teacher.setId(teachers.get(i).getId());
				teacher.setLink(CommonMethods.parseLink(teachers.get(i).getLink()));
				
				try
				{
					TeacherParser tp = new TeacherParser(teacher);
					tp.parse(true);
					teachersTimetable.put(teacher.getId(), teacher);
				} 
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	private void initBuildings()
	{
		BuildingsParser bp = new BuildingsParser();
		
		try
		{
			ArrayList<Building> buildingsLocal = bp.parse(new URL("http://plan.uz.zgora.pl/sale_lista_budynkow.php?pTyp=P"));
			
			for (int i = 0; i < buildingsLocal.size(); i++)
			{
				buildings.put(buildingsLocal.get(i).getId(), buildingsLocal.get(i));
			}
		} 
		catch (MalformedURLException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	private void initBuildingsWithLectureRooms()
	{
		Iterator<Building> buildingsLocal = buildings.values().iterator();
		
		while(buildingsLocal.hasNext())
		{
			Building building = buildingsLocal.next();
			Building buil = new Building(building.getName(), building.getDescription(), building.getAddress());
			buil.setLink(CommonMethods.parseLink(building.getLink()));
			buil.setId(building.getId());
			
			LectureRoomsParser lrp = new LectureRoomsParser(buil);
			
			try
			{
				lrp.parse(true);
				buildingsWithLectureRooms.put(buil.getId(), buil);
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	private void initLectureRoomsTimetable()
	{
		Iterator<Building> buildingsLocal = buildingsWithLectureRooms.values().iterator();
		
		while(buildingsLocal.hasNext())
		{
			Building building = buildingsLocal.next();
			ArrayList<LectureRoom> lectureRooms = building.getLectureRooms();
			
			for (int i = 0; i < lectureRooms.size(); i++)
			{
				LectureRoom lectureRoom = new LectureRoom(lectureRooms.get(i).getName(), lectureRooms.get(i).getCapacity(), lectureRooms.get(i).getType(), lectureRooms.get(i).getUnit());
				lectureRoom.setId(lectureRooms.get(i).getId());
				lectureRoom.setLink(CommonMethods.parseLink(lectureRooms.get(i).getLink()));
				
				try
				{
					LectureRoomParser lrp = new LectureRoomParser(lectureRoom);
					lrp.parse(true);
					lectureRoomsTimetable.put(lectureRoom.getId(), lectureRoom);
				} 
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	private void initCalendarListAndCalendars()
	{
		MainCalendarsParser mcp = new MainCalendarsParser();
		
		try
		{
			ArrayList<CalendarList> mainCalendars = mcp.parse(new URL("http://plan.uz.zgora.pl/kalendarze_lista.php"));
			
			for (int i = 0; i < mainCalendars.size(); i++)
			{
				CalendarsParser cp = new CalendarsParser(mainCalendars.get(i));
				CalendarList mainCalendar = cp.parse(true);
				
				CalendarList newMainCalendar = new CalendarList(mainCalendar.getName(), mainCalendar.getDescription(), mainCalendar.getWarning(), mainCalendar.getShared());
				newMainCalendar.setId(mainCalendar.getId());
				newMainCalendar.setLink(mainCalendar.getLink());
				
				ArrayList<Calendar> calendarsLocal = mainCalendar.getCalendars();
				
				for (int j = 0; j < calendarsLocal.size(); j++)
				{
					calendars.put(calendarsLocal.get(j).getId(), calendarsLocal.get(j));
					newMainCalendar.createCalendar(calendarsLocal.get(j).getId(), calendarsLocal.get(j).getName());
				}

				calendarList.put(newMainCalendar.getId(), newMainCalendar);
			}
		} 
		catch (MalformedURLException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	
	private void initTeachersReservations()
	{
		Iterator<Teacher> teachers = teachersTimetable.values().iterator();
		while(teachers.hasNext())
		{
			Teacher teacher = teachers.next();
			
			Reservation reservation = new Reservation(teacher.getName(), teacher.getUnit());
			reservation.setId(teacher.getId());
			reservation.setLink(CommonMethods.parseLink(teacher.getLink()) + "&pTyp=R");
			
			try
			{
				ReservationTParser lrp = new ReservationTParser(reservation);
				lrp.parse();
				teachersReservations.put(reservation.getId(), reservation);
			} 
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	private void initLectureRoomsReservations()
	{
		Iterator<Building> buildings = buildingsWithLectureRooms.values().iterator();
		while(buildings.hasNext())
		{
			Building building = buildings.next();
			ArrayList<LectureRoom> lectureRooms = building.getLectureRooms();
			
			for (int i = 0; i < lectureRooms.size(); i++)
			{
				Reservation reservation = new Reservation(lectureRooms.get(i).getName(), lectureRooms.get(i).getCapacity(), lectureRooms.get(i).getType(), lectureRooms.get(i).getUnit());
				reservation.setId(lectureRooms.get(i).getId());
				reservation.setLink(CommonMethods.parseLink(lectureRooms.get(i).getLink()) + "&pTyp=R");
				
				try
				{
					ReservationLRParser lrp = new ReservationLRParser(reservation);
					lrp.parse();
					lectureRoomsReservations.put(reservation.getId(), reservation);
				} 
				catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	private void startTime()
	{
		startTime = System.currentTimeMillis();
	}
	
	public Map<String, Department> getDepartments()
	{
		return departments;
	}

	public Map<String, Department> getDepartmentsWithTeachers()
	{
		return departmentsWithTeachers;
	}

	public Map<String, Teacher> getTeachersTimetable()
	{
		return teachersTimetable;
	}

	public Map<String, Reservation> getTeachersReservations()
	{
		return teachersReservations;
	}

	public Map<String, Department> getDepartmentsWithDirections()
	{
		return departmentsWithDirections;
	}

	public Map<String, Direction> getDirectionsWithGroups()
	{
		return directionsWithGroups;
	}

	public Map<String, Group> getGroupsTimetable()
	{
		return groupsTimetable;
	}

	public Map<String, Building> getBuildings()
	{
		return buildings;
	}

	public Map<String, Building> getBuildingsWithLectureRooms()
	{
		return buildingsWithLectureRooms;
	}

	public Map<String, LectureRoom> getLectureRoomsTimetable()
	{
		return lectureRoomsTimetable;
	}

	public Map<String, Reservation> getLectureRoomsReservations()
	{
		return lectureRoomsReservations;
	}

	public Map<String, CalendarList> getCalendarList()
	{
		return calendarList;
	}

	public Map<String, Calendar> getCalendars()
	{
		return calendars;
	}

	private long countTime()
	{
		return System.currentTimeMillis() - startTime;
	}

	public void serialize()
	{
		Utilities.serialize(departmentsWithDirections, files.get("0"));
		Utilities.serialize(directionsWithGroups, files.get("1"));
		Utilities.serialize(groupsTimetable, files.get("2"));
		Utilities.serialize(departments, files.get("3"));
		Utilities.serialize(departmentsWithTeachers, files.get("4"));
		Utilities.serialize(teachersTimetable, files.get("5"));
		Utilities.serialize(buildings, files.get("6"));
		Utilities.serialize(buildingsWithLectureRooms, files.get("7"));
		Utilities.serialize(lectureRoomsTimetable, files.get("8"));
		Utilities.serialize(calendarList, files.get("9"));
		Utilities.serialize(calendars, files.get("10"));
		Utilities.serialize(teachersReservations, files.get("11"));
		Utilities.serialize(lectureRoomsReservations, files.get("12"));
	}
}
